const Uninitialized = -1;
const Pending = 0;
const Resolved = 1;
const Rejected = 2;

/**
 * @param {object} payload
 * @returns {unknown}
 */
function lazyInitializer(payload) {
  if (payload._status === Uninitialized) {
    const ctor = payload._result;
    const thenable = ctor();
    thenable.then(
      (moduleObject) => {
        if (payload._status === Pending || payload._status === Uninitialized) {
          const resolved = payload;
          resolved._status = Resolved;
          resolved._result = moduleObject;
        }
      },
      (error) => {
        if (payload._status === Pending || payload._status === Uninitialized) {
          const rejected = payload;
          rejected._status = Rejected;
          rejected._result = error;
        }
      },
    );
    if (payload._status === Uninitialized) {
      const pending = payload;
      pending._status = Pending;
      pending._result = thenable;
    }
  }
  if (payload._status === Resolved) {
    const moduleObject = payload._result;
    // if (__DEV__) {
    //     if (moduleObject === undefined) {
    //         console.error('lazy: Expected the result of a dynamic import() call. ' +
    //             'Instead received: %s\n\nYour code should look like: \n  ' +
    //             'const MyComponent = lazy(() => import(\'./MyComponent\'))\n\n' +
    //             'Did you accidentally put curly braces around the import?', moduleObject);
    //     }
    //     if (!('default' in moduleObject)) {
    //         console.error('lazy: Expected the result of a dynamic import() call. ' +
    //             'Instead received: %s\n\nYour code should look like: \n  ' +
    //             'const MyComponent = lazy(() => import(\'./MyComponent\'))', moduleObject);
    //     }
    // }
    return moduleObject.default;
  }
  throw payload._result;
}

/**
 * @param {function} ctor
 * @returns {unknown}
 */
export function lazy(ctor) {
  const payload = {
    _status: Uninitialized,
    _result: ctor,
  };
  const lazyType = {
    $$typeof: REACT_LAZY_TYPE,
    _payload: payload,
    _init: lazyInitializer,
  };
  if (!disableDefaultPropsExceptForClasses && __DEV__) {
    let defaultProps;
    Object.defineProperties(lazyType, {
      defaultProps: {
        configurable: true,
        get() {
          return defaultProps;
        },
        set(newDefaultProps) {
          console.error(
            "It is not supported to assign `defaultProps` to " +
              "a lazy component import. Either specify them where the component " +
              "is defined, or create a wrapping component around it.",
          );
          defaultProps = newDefaultProps;
          Object.defineProperty(lazyType, "defaultProps", {
            enumerable: true,
          });
        },
      },
    });
  }
  return lazyType;
}
